/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package snakesandladders;

import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Stack;
import java.util.Vector;

/**
 *
 * @author andres
 */
public class Territorio
{
    Matriz matrizJugadas;
    int tamanoTablero, xMaquina,yMaquina,profundidadMax,desicionI,desicionJ;
    Jugador jugador1,maquina;
    Stack <Nodo> pilaNodos;
    Stack pilaMatrices;
    PriorityQueue<Nodo> nodosHoja;
    PriorityQueue<Matriz> matricesHoja;


    public Territorio(Matriz matrizJuego)
    {
            xMaquina=yMaquina=0;
            tamanoTablero=5;
            profundidadMax=4;

            matrizJugadas=matrizJuego;

            Comparator comparador=new MiComparador();
            Comparator comparador2=new MiComparadorMatriz();

            pilaNodos= new Stack();
            pilaMatrices=new Stack();
            nodosHoja=new PriorityQueue<Nodo>(100,comparador);
            matricesHoja=new PriorityQueue<Matriz>(100,comparador2);

            crearJugadores();
            jugadaMaquina();
    }

    public void crearJugadores()
    {
        jugador1=new Jugador(1);
        maquina=new Jugador(2);

        jugador1.setIPosCabeza(matrizJugadas.getiJugador1());
        jugador1.setJPosCabeza(matrizJugadas.getjJugador1());

         maquina.setIPosCabeza(matrizJugadas.getiMaquina());
        maquina.setJPosCabeza(matrizJugadas.getjMaquina());
    }



    public void jugadaMaquina()
    {
        //System.out.println("minimax inicio");
        arbolMinimax();
        //System.out.println("minimax fin");
    }

    public int numeroCeldasLibres(Matriz matriz,int jugador)
    {
        int iJugador,jJugador,iMaquina,jMaquina,celdasLibresJugador;
        iJugador=jJugador=celdasLibresJugador=0;

        
        jMaquina=matriz.getjMaquina();
        iMaquina=matriz.getiMaquina();

        if(jugador==1)
        {
            iJugador=matriz.getiJugador1();
            jJugador=matriz.getjJugador1();
        }
        else
        {
             iJugador=matriz.getiMaquina();
            jJugador=matriz.getjMaquina();
        }

         for(int i=iJugador-1; i<iJugador+2 ; i++)
        {
            for(int j=jJugador-1; j<jJugador+2; j++)
            {
                if(i>=0 && i<tamanoTablero && j>=0 && j<tamanoTablero)
                {
                    if(matriz.getValorPosicion(i, j)==0)
                    {
                        celdasLibresJugador++;
                    }
                }
            }
        }

        return celdasLibresJugador;
    }


    public void calcularUtilidadNodo(Nodo nodo, Matriz matrizNodo)
    {
       
        int celdasLibresMaq,celdasLibresJug;
        celdasLibresJug=numeroCeldasLibres(matrizNodo,1);
        celdasLibresMaq=numeroCeldasLibres(matrizNodo, 2);

        if(celdasLibresMaq>0 && celdasLibresJug==0)
        {
            nodo.setUtilidad((int)Double.POSITIVE_INFINITY);
        }

        else if(celdasLibresJug==0 && celdasLibresMaq==0)
        {
            if(matrizNodo.numCeldasJugador1<matrizNodo.numCeldasMaquina)
            {
                 nodo.setUtilidad((int)Double.POSITIVE_INFINITY);
            }
            else
            {
                nodo.setUtilidad((int)Double.NEGATIVE_INFINITY);
            }
        }
        else if(celdasLibresMaq==0 && celdasLibresJug>0)
        {
            nodo.setUtilidad((int)Double.NEGATIVE_INFINITY);
        }
        else
        {
            nodo.setUtilidad(celdasLibresMaq-celdasLibresJug);
        }

        /*for(int i=0; i<tamanoTablero; i++)
        {
            String s="";
            for(int j=0; j<tamanoTablero; j++)
            {
                 s=s+matrizNodo.getValorPosicion(i, j)+" ";
            }
            System.out.println(s);
        }*/
       // System.out.println((celdasLibresMaq-celdasLibresJug)+"\n");
       //System.out.println("utilidad "+iJugador1+" "+jJugador1+" maq "+iMaquina+" "+jMaquina+" valor: "+utilidad);

    }



    public int[][] copiarMatriz(int matrizACopiar[][])
    {
        int [][] matriz;
        matriz=new int[5][5];
        int valor=0;

        for(int i=0; i<tamanoTablero ; i++)
        {
            for(int j=0; j<tamanoTablero; j++)
            {
                valor=matrizACopiar[i][j];
                matriz[i][j]=valor;

            }
        }

        return matriz;
    }

    public void encolarNodosLibres(Nodo nodo)
    {
        int iCabeza,jCabeza;
        
       /* iCabeza=nodo.getI();
        jCabeza=nodo.getJ();*/
        int numNodos=0;
        
        Matriz matrizCabeza;
        matrizCabeza=(Matriz)pilaMatrices.pop();

        if(nodo.getTipo().equals("MAX"))
        {
            iCabeza=matrizCabeza.getiMaquina();
            jCabeza=matrizCabeza.getjMaquina();
        }
        else
        {
            iCabeza=matrizCabeza.getiJugador1();
            jCabeza=matrizCabeza.getjJugador1();
        }

       // System.out.println("a expandir "+iCabeza+" "+jCabeza);
        int [][]matriz;
        matriz=copiarMatriz(matrizCabeza.getMatriz());

         if(nodo.getProfundidad()==4)
          {
            calcularUtilidadNodo(nodo,matrizCabeza);
           // System.out.println("assss "+matrizCabeza.getiJugador1()+" "+matrizCabeza.getjJugador1()+" ytu "+matrizCabeza.getiMaquina()+" "+matrizCabeza.getjMaquina() );
             nodosHoja.add(nodo);
             matricesHoja.add(matrizCabeza);
             return;
          }


        for(int i=iCabeza-1; i<iCabeza+2 ; i++)
        {
             //System.out.println("asdf "+matriz[3][2]);
            for(int j=jCabeza-1; j<jCabeza+2; j++)
            {
                int[][] matrizTmp;
                matrizTmp=copiarMatriz(matriz);
                
                if(i>=0 && i<tamanoTablero && j>=0 && j<tamanoTablero)
                {
                    if(matrizTmp[i][j]==0)
                    {
                       // System.out.println(nodo.getI()+" "+nodo.getJ()+"hola "+i+" "+j);
                        Nodo nodoHijo;
                        Matriz m;
                        numNodos++;
                        /*
                        System.out.println("hola "+ nodo.getI());
                        System.out.println("hola "+ nodo.getJ());*/

                        if(nodo.getTipo().equals("MAX"))
                        {
                            nodoHijo=new Nodo(i,j,"MIN",nodo.getProfundidad()+1);
                            nodoHijo.setUtilidad((int)Double.POSITIVE_INFINITY);
                           // System.out.println("copia "+matriz[2][1]);
                            matrizTmp[i][j]=2;
                           // System.out.println("copia// "+matriz[2][1]);
                           // System.out.println("creo min "+i+" "+j);
                            m=new Matriz(matrizTmp);
                            m.setiMaquina(i);
                            m.setjMaquina(j);
                            m.setiJugador1(matrizCabeza.getiJugador1());
                            m.setjJugador1(matrizCabeza.getjJugador1());
                            m.setProfundidad(nodo.getProfundidad()+1);
                            //int tmp=numeroCeldasLibres(m, 2);
                           // tmp-=numeroCeldasLibres(m, 1);
                           // m.setCeldasDisp(matrizCabeza.getCeldasDisp()+tmp);
                            pilaMatrices.push(m);
                        }
                        else
                        {
                            nodoHijo=new Nodo(i,j,"MAX",nodo.getProfundidad()+1);
                            nodoHijo.setUtilidad((int)Double.NEGATIVE_INFINITY);
                            
                            matrizTmp[i][j]=1;
                            //System.out.println("creo max "+i+" "+j);
                            m=new Matriz(matrizTmp);
                            m.setiMaquina(matrizCabeza.getiMaquina());
                            m.setjMaquina(matrizCabeza.getjMaquina());
                            m.setiJugador1(i);
                            m.setjJugador1(j);
                            m.setProfundidad(nodo.getProfundidad()+1);
                           // int tmp=numeroCeldasLibres(m, 2);
                            //tmp-=numeroCeldasLibres(m, 1);
                            //m.setCeldasDisp(matrizCabeza.getCeldasDisp()+tmp);
                            
                            pilaMatrices.push(m);
                        }

                        nodoHijo.setNodoPadre(nodo);
                        pilaNodos.push(nodoHijo);

                    }
                    else{/*System.out.println("nn "+i+" "+j+" v: "+matrizTmp[i][j]);*/}
                }
            }
        }

          if(numNodos==0)
          {
            calcularUtilidadNodo(nodo,matrizCabeza);
           // System.out.println("assss "+matrizCabeza.getiJugador1()+" "+matrizCabeza.getjJugador1()+" ytu "+matrizCabeza.getiMaquina()+" "+matrizCabeza.getjMaquina() );
          }
          nodosHoja.add(nodo);
          matricesHoja.add(matrizCabeza);
 
    }

    public void calcularDesicionMinimax(Nodo nodoRaiz)
    {
        Matriz matriz=matricesHoja.poll();

        maquina.setIPosCabeza(nodoRaiz.desicionI);
        maquina.setJPosCabeza(nodoRaiz.desicionJ);
        
        desicionI=maquina.getIPosCabeza();
        desicionJ=maquina.getJPosCabeza();

        //System.out.println("raiz "+nodoRaiz.desicionI+" "+nodoRaiz.desicionJ);
        //System.out.println("matrices: "+matriz.getiMaquina()+"  "+matriz.getjMaquina());

    }


    public void calcularUtilidades()
    {
    
        int celdasJugador1,celdasMaquina;
 

            while(nodosHoja.size()!=1)
            {
                matricesHoja.poll();
                Nodo nodoHoja=nodosHoja.poll();
                Nodo nodoPadre=nodoHoja.getNodoPadre();                
          
                if(nodoPadre.getTipo().equals("MAX"))
                {
                    if(nodoPadre.getUtilidad()<nodoHoja.getUtilidad())
                    {
                        nodoPadre.setUtilidad(nodoHoja.getUtilidad());
                        if(nodoPadre.isRaiz())
                        {
                            nodoPadre.setDesicionI(nodoHoja.i);
                            nodoPadre.setDesicionJ(nodoHoja.j);
                        }
                    }
                    else if(nodoPadre.getUtilidad()==nodoHoja.getUtilidad())
                    {
                        if(nodoPadre.getUtilidad()>0)
                        {
                                if(nodoHoja.getProfDesicion()<nodoPadre.getProfDesicion())
                                {
                                    nodoPadre.setProfDesicion(nodoHoja.getProfDesicion());
                                    if(nodoPadre.isRaiz())
                                        {
                                            nodoPadre.setDesicionI(nodoHoja.i);
                                            nodoPadre.setDesicionJ(nodoHoja.j);
                                        }
                                }
                        }
                        else
                        {
                            if(nodoHoja.getProfDesicion()>nodoPadre.getProfDesicion())
                                {
                                    nodoPadre.setProfDesicion(nodoHoja.getProfDesicion());
                                    if(nodoPadre.isRaiz())
                                    {
                                        nodoPadre.setDesicionI(nodoHoja.i);
                                        nodoPadre.setDesicionJ(nodoHoja.j);
                                    }
                                }
                        }
                    }
                    
                }
                 else
                 {
                    if(nodoPadre.getUtilidad()>nodoHoja.getUtilidad())
                    {
                        nodoPadre.setUtilidad(nodoHoja.getUtilidad());
                        /*nodoPadre.setDesicionI(nodoHoja.i);
                        nodoPadre.setDesicionJ(nodoHoja.j);*/
                    }
                    else if(nodoPadre.getUtilidad()==nodoHoja.getUtilidad())
                    {
                        if(nodoPadre.getUtilidad()>0)
                        {
                                if(nodoHoja.getProfDesicion()<nodoPadre.getProfDesicion())
                                {
                                    nodoPadre.setProfDesicion(nodoHoja.getProfDesicion());
                                    if(nodoPadre.isRaiz())
                                        {
                                            nodoPadre.setDesicionI(nodoHoja.i);
                                            nodoPadre.setDesicionJ(nodoHoja.j);
                                        }
                                }
                        }
                        else
                        {
                            if(nodoHoja.getProfDesicion()>nodoPadre.getProfDesicion())
                                {
                                    nodoPadre.setProfDesicion(nodoHoja.getProfDesicion());
                                    if(nodoPadre.isRaiz())
                                    {
                                        nodoPadre.setDesicionI(nodoHoja.i);
                                        nodoPadre.setDesicionJ(nodoHoja.j);
                                    }
                                }
                        }
                    }
                 }
               
            }
         Nodo nodoRaiz=nodosHoja.poll();
       
        calcularDesicionMinimax(nodoRaiz);
        
    }


    public void arbolMinimax()
    {

        int iCabeza,jCabeza,celdasLibres,numNodos;
         iCabeza=jCabeza=numNodos=0;

         iCabeza=maquina.getIPosCabeza();
         jCabeza=maquina.getJPosCabeza();

         
         int [][]matriz;
         matriz=copiarMatriz(matrizJugadas.getMatriz());
         Matriz m=new Matriz(matriz);

         
         m.setiJugador1(matrizJugadas.getiJugador1());
         m.setjJugador1(matrizJugadas.getjJugador1());
         m.setiMaquina(matrizJugadas.getiMaquina());
         m.setjMaquina(matrizJugadas.getjMaquina());
         m.setProfundidad(0);

         pilaMatrices.push(m);

         Nodo raiz=new Nodo(iCabeza,jCabeza,"MAX",0);
         raiz.setUtilidad((int)Double.NEGATIVE_INFINITY);
         raiz.setRaiz(true);
         pilaNodos.push(raiz);         
         
         int nodosAExpandir=0;

       /* for(int n=0; n<profundidadMax; n++)
        {           
            
            nodosAExpandir=pilaNodos.size();

            for(int i=0; i<nodosAExpandir; i++)
            {*/
               while(pilaNodos.size()!=0)
               {
                Nodo cabeza=pilaNodos.pop();
               encolarNodosLibres(cabeza);     
        }
          /*  }

        }*/
         calcularUtilidades();

    }

    public int getDesicionI() {
        return desicionI;
    }

    public int getDesicionJ() {
        return desicionJ;
    }

    

}
